using System;
using System.Threading;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using needle.UI.Controls.Flat.Windows.Forms;
using needle.UI.Controls.Flat.Windows.Forms.Collections;

namespace needle.UI.Controls.Flat.Windows.Forms
{
	[System.ComponentModel.ToolboxItem(true),
	Designer(typeof(needle.UI.Controls.Flat.Windows.Forms.MenuListBoxDesigner))]
	public class MenuListBox : needle.UI.Controls.Flat.Windows.Forms.ControlBase, IFlashabledControl
	{
		private needle.UI.Controls.Flat.Windows.Forms.ListBoxBase mListBox;
		private System.ComponentModel.IContainer components = null;
		private MenuListBoxItemCollection items = new MenuListBoxItemCollection();
		private Font titleFont = new Font("Verdana", 12, FontStyle.Bold);
		private Image selectedImage = null;
		private int imageTopOffSet = 5;
		private int descriptionLeftOffSet = 11;
		private int descriptionTopOffSet = 2;

		//Style Neo, default!!
		private Color m_TextColor = Color.Black;
		private Color m_EditDisabledColor = Color.FromArgb(238, 238, 225);
		private Color m_EditReadOnlyColor = Color.FromArgb(238, 238, 225);
		private Color m_EditFocusedColor = Color.White;
		private Color m_EditColor = Color.FromArgb(242, 242, 228);
		private Color m_FlashColor = Color.FromArgb(170, 170, 221);
		private Color m_SelectionColor = StyleGuide.InteliSelectionColor(PlansColors.NeoTheOne);

		[Category("Property Changed")]
		public event EventHandler SelectedValueChanged;

		[Category("Behavior")]
		public event EventHandler SelectedIndexChanged;

		#region Constructors
		
		public MenuListBox()
		{
			InitializeComponent();

			mListBox.LostFocus  += new System.EventHandler(this.mListBox_OnLostFocus);
			mListBox.GotFocus   += new System.EventHandler(this.mListBox_OnGotFocus);

			items.Clearing += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionClearEventHandler(OnClearingItens);
			items.Cleared += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionClearEventHandler(OnClearedItens);
			items.Inserting += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnInsertingItem);
			items.Inserted += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnInsertedItem);
			items.Removing += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnRemovingItem);
			items.Removed += new needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventHandler(OnRemovedItem);
		}

		#endregion

		#region Dispose
		
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				mListBox.LostFocus  -= new System.EventHandler(this.mListBox_OnLostFocus);
				mListBox.GotFocus   -= new System.EventHandler(this.mListBox_OnGotFocus);

				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#endregion

		#region Designer generated code
		private void InitializeComponent()
		{
			this.mListBox = new needle.UI.Controls.Flat.Windows.Forms.ListBoxBase();
			this.SuspendLayout();
			// 
			// mListBox
			// 
			this.mListBox.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(242)), ((System.Byte)(242)), ((System.Byte)(228)));
			this.mListBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
			this.mListBox.Dock = System.Windows.Forms.DockStyle.Fill;
			this.mListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
			this.mListBox.Location = new System.Drawing.Point(1, 1);
			this.mListBox.Name = "mListBox";
			this.mListBox.SelectionColor = System.Drawing.Color.FromArgb(((System.Byte)(187)), ((System.Byte)(194)), ((System.Byte)(214)));
			this.mListBox.Size = new System.Drawing.Size(148, 174);
			this.mListBox.TabIndex = 1;
			this.mListBox.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.mListBox_MeasureItem);
			this.mListBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.mListBox_KeyDown);
			this.mListBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.mListBox_KeyPress);
			this.mListBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.mListBox_KeyUp);
			this.mListBox.SelectedValueChanged += new System.EventHandler(this.mListBox_SelectedValueChanged);
			this.mListBox.SelectedIndexChanged += new System.EventHandler(this.mListBox_SelectedIndexChanged);
			this.mListBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.mListBox_DrawItem);
			// 
			// MenuListBox
			// 
			this.Controls.AddRange(new System.Windows.Forms.Control[] {
																		  this.mListBox});
			this.DockPadding.All = 1;
			this.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.Name = "MenuListBox";
			this.Size = new System.Drawing.Size(150, 176);
			this.ResumeLayout(false);

		}
		#endregion

		#region Events handlers
				
		private void mListBox_OnGotFocus(object sender, System.EventArgs e)
		{
			this.BackColor = this.EditFocusedColor;			
		}

		private void mListBox_OnLostFocus(object sender, System.EventArgs e)
		{
			this.BackColor = this.Style!=null? 
				this.Style.InteliEditColor(false,this.Enabled):
				StyleGuide.InteliEditColor(false,this.Enabled,this.m_EditColor, 
				this.m_EditReadOnlyColor, this.m_EditDisabledColor);
			//
			DrawControl(this.ContainsFocus);
		}

		private void mListBox_SelectedValueChanged(object sender, System.EventArgs e)
		{
			if (this.SelectedValueChanged != null)
				this.SelectedValueChanged(sender,e);
		}

		private void mListBox_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			if (this.SelectedIndexChanged != null)
				this.SelectedIndexChanged(sender,e);
		}

		private void mListBox_MeasureItem(object sender, System.Windows.Forms.MeasureItemEventArgs e)
		{
			if (e.Index != -1)
			{
				e.ItemHeight = (int)e.Graphics.MeasureString((string)this.mListBox.Items[e.Index],
					this.titleFont, this.mListBox.Width).Height + 20 + (int)titleFont.SizeInPoints;
			}
		}
		
		private void mListBox_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
		{
			this.mListBox.SuspendLayout();
			this.SuspendLayout();
			
			if (e.Index != -1)
			{
				if (this.mListBox.Enabled)
				{
					Text = e.State.ToString();

					if (e.State.ToString().IndexOf("Selected") != -1)
					{
						using (Brush b = new SolidBrush(this.m_SelectionColor))
						{
							e.Graphics.FillRectangle(b, e.Bounds.Left, e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
						}
					}
					else
					{
						using (Brush backBrush = new SolidBrush(this.m_EditColor))
						{
							e.Graphics.FillRectangle(backBrush, e.Bounds.Left, e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
						}
					}
				}

				e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
				string textItem = (string)this.mListBox.Items[e.Index];

				if (textItem.Length>0)
				{
					StringFormat format  = new StringFormat();
					format.LineAlignment = StringAlignment.Near;
					format.Alignment = StringAlignment.Near;
					
					string[] lines = textItem.Split('\n');

					for(int i=0; i<lines.Length; i++)
					{
						string line = lines[i];
	
						using (Brush brush1=new SolidBrush(this.m_TextColor))
						{
							if (i==0)
							{
								format.HotkeyPrefix = HotkeyPrefix.Show;
								e.Graphics.DrawString(line, this.titleFont,
									brush1, new RectangleF(e.Bounds.Left+ (selectedImage!=null?selectedImage.Width:0)+10, 
									e.Bounds.Top,e.Bounds.Width-20, e.Bounds.Height), format);

							}
							else
							{
								format.HotkeyPrefix = HotkeyPrefix.None;
								e.Graphics.DrawString("\n"+line, this.Font,
									brush1, new RectangleF(e.Bounds.Left+(selectedImage!=null?selectedImage.Width:0)+this.descriptionLeftOffSet, 
									e.Bounds.Top+titleFont.SizeInPoints+this.descriptionTopOffSet, e.Bounds.Width-20, e.Bounds.Height), format);
							}
						}
					}
				}				

				if (selectedImage!=null) 
				{
					e.Graphics.DrawImage(selectedImage, 4, e.Bounds.Top + this.imageTopOffSet);
				}
			}		
	
			this.mListBox.ResumeLayout();
			this.ResumeLayout();			
		}

		private void mListBox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			this.OnKeyDown(e);
		}

		private void mListBox_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
		{
			this.OnKeyPress(e);
		}

		private void mListBox_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
		{
			this.OnKeyUp(e);
		}

		#endregion

		#region Virtuals

		protected virtual void OnClearingItens(object sender, EventArgs e)
		{
		}

		protected virtual void OnClearedItens(object sender, EventArgs e)
		{
			this.mListBox.Items.Clear();
		}

		protected virtual void OnInsertingItem(object sender, needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventArgs e)
		{
		}

		protected virtual void OnInsertedItem(object sender, needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventArgs e)
		{
			MenuListBoxItem item = sender as MenuListBoxItem;
			this.AddItem(item);
		}

		protected virtual void OnRemovingItem(object sender, needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventArgs e)
		{
		}

		protected virtual void OnRemovedItem(object sender, needle.UI.Controls.Flat.Windows.Forms.Collections.CollectionChangeEventArgs e)
		{
			MenuListBoxItem item = this.items[e.Index];

			if (item!=null)
			{
				this.RemoveItem(item, e.Index);
				this.Invalidate();
			}
		}

		protected virtual void RemoveItem(MenuListBoxItem item, int index)
		{
			if (item != null)
				this.mListBox.Items.RemoveAt(index);
		}

		protected virtual void AddItem(MenuListBoxItem item)
		{
			if (item != null)
				this.mListBox.Items.Add(item.Title + "\n" + item.Description.Replace("\n", String.Empty));
		}

		#endregion

		#region Overrides

		protected override bool ProcessMnemonic(char charCode)
		{
			base.ProcessMnemonic(charCode);

			if (this.Enabled)
			{
				int index = 0;
				foreach(string item in this.mListBox.Items)
				{
					if (IsMnemonic(charCode, item))
					{
						this.Focus();
						this.mListBox.SelectedIndex = index;
						return true;
					}
					index++;
				}

				return false;
			}
			else {return false;}
		}

		protected override void OnStyleChanged(object sender, StyleEventArgs args)
		{
			base.OnStyleChanged(sender, args);

			if (args.PropertyName == "FlashColor") {this.FlashColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "TextColor") {this.TextColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditColor") {this.EditColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditFocusedColor") {this.EditFocusedColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditReadOnlyColor") {this.EditReadOnlyColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "EditDisabledColor") {this.EditDisabledColor = (Color)args.PropertyValue;}
			else if (args.PropertyName == "SelectionColor") {this.SelectionColor = (Color)args.PropertyValue;}

			this.BackColor = this.Style!=null? 
				this.Style.InteliEditColor(false,this.Enabled):
				StyleGuide.InteliEditColor(false,this.Enabled,this.m_EditColor, 
				this.m_EditReadOnlyColor, this.m_EditDisabledColor);

			this.Invalidate(true);
		}

		protected override void OnPlansOfColorsChanged(object sender, PlansOfColorsChangedEventArgs args)
		{
			base.OnPlansOfColorsChanged(sender, args);

			if (this.Style!=null)
			{
				this.FlashColor = this.Style.FlashColor;
				this.EditColor = this.Style.EditColor;
				this.EditFocusedColor = this.Style.EditFocusedColor;
				this.EditReadOnlyColor = this.Style.EditReadOnlyColor;
				this.EditDisabledColor = this.Style.EditDisabledColor;
				this.TextColor = this.Style.TextColor;
				this.mListBox.SelectionColor = this.Style.SelectionColor;
				this.SelectionColor = this.Style.SelectionColor;

				this.BackColor = this.Style!=null? 
					this.Style.InteliEditColor(false,this.Enabled):
					StyleGuide.InteliEditColor(false,this.Enabled,this.m_EditColor, 
					this.m_EditReadOnlyColor, this.m_EditDisabledColor);
			}

			this.Invalidate(true);
		}

		protected override void OnEnabledChanged(EventArgs e)
		{
			base.OnEnabledChanged(e);
			this.BackColor = this.Style!=null? 
				this.Style.InteliEditColor(false,this.Enabled):
				StyleGuide.InteliEditColor(false,this.Enabled,this.m_EditColor, 
				this.m_EditReadOnlyColor, this.m_EditDisabledColor);
		}

		#endregion

		#region Internal helpers

		private void ThreadFlashControl()
		{
			for (int i=1; i<=8;i++)
			{
				if(this.mListBox.BackColor == this.EditColor)
				{
					this.mListBox.BackColor = this.FlashColor;
				}
				else
				{
					this.mListBox.BackColor = this.EditColor;
				}
				Thread.Sleep(150);
			}

			this.mListBox.BackColor = this.EditColor;
		}

		#endregion

		#region Properties

		[Bindable(true),
		Browsable(false)]
		public int SelectedIndex
		{
			get{ return mListBox.SelectedIndex; }
			set{ mListBox.SelectedIndex = value; }
		}

		[Category("Appearance")]
		public Font TitleFont
		{
			get {return this.titleFont;}
			set 
			{
				this.titleFont = value;
				this.Invalidate(true);
			}
		}
		
		[Browsable(false),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public new Color BackColor
		{
			get{ return base.BackColor; }

			set
			{
				base.BackColor      = value;
				if (mListBox!=null) mListBox.BackColor = value;
			}
		}

		[Browsable(false)]
		public override Color ForeColor
		{
			get{ return base.ForeColor; }

			set
			{
				base.ForeColor      = value;
				mListBox.ForeColor = value;
			}
		}

		[Category("Style")]
		public Color TextColor
		{
			get {return m_TextColor;}
			set 
			{
				m_TextColor = value;
				this.mListBox.ForeColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color FlashColor
		{
			get {return m_FlashColor;}
			set 
			{
				m_FlashColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color EditColor
		{
			get {return m_EditColor;}
			set 
			{
				m_EditColor = value;
				this.mListBox.BackColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color EditFocusedColor
		{
			get {return m_EditFocusedColor;}
			set 
			{
				m_EditFocusedColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color EditReadOnlyColor
		{
			get {return m_EditReadOnlyColor;}
			set 
			{
				m_EditReadOnlyColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color EditDisabledColor
		{
			get {return m_EditDisabledColor;}
			set 
			{
				m_EditDisabledColor = value;
				this.Invalidate();
			}
		}

		[Category("Style")]
		public Color SelectionColor
		{
			get {return m_SelectionColor;}
			set 
			{
				m_SelectionColor = value;
				this.Invalidate();
			}
		}

		[Category("Behavior"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		Localizable(true)]
		public MenuListBoxItemCollection Items
		{
			get {return this.items;}
		}

		[Category("Appearance")]
		public Image ItemImage
		{
			get{return this.selectedImage;}
			set
			{
				this.selectedImage = value;
				this.Invalidate(true);
			}
		}

		[Category("Behavior"),
		DefaultValue(5)]
		public int ImageTopOffSet
		{
			get{return this.imageTopOffSet;}
			set
			{
				this.imageTopOffSet = value;
				this.Invalidate(true);
			}
		}

		[Category("Behavior"),
		DefaultValue(11)]
		public int DescriptionLeftOffSet
		{
			get{return this.descriptionLeftOffSet;}
			set
			{
				this.descriptionLeftOffSet = value;
				this.Invalidate(true);
			}
		}

		[Category("Behavior"),
		DefaultValue(2)]
		public int DescriptionTopOffSet
		{
			get{return this.descriptionTopOffSet;}
			set
			{
				this.descriptionTopOffSet = value;
				this.Invalidate(true);
			}
		}

		#endregion

		#region IFlashabledControl

		public void FlashControl()
		{
			Thread m_Thread = new Thread(new ThreadStart(ThreadFlashControl));
			m_Thread.Start();
		}
		
		#endregion
	}
}

